#pragma once

#include <iostream>
#include <queue>
#include <string>
#include <pthread.h>
#include <functional>

static const int gmaxcap = 500;

template <class T>
class BlockQueue
{
public:
    BlockQueue(const int &maxcap = gmaxcap):_maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }

    void push(const T& in)
    {
        pthread_mutex_lock(&_mutex);

        //1、判断
        while(is_full())
        {
            pthread_cond_wait(&_pcond,&_mutex);//因为满了，无法生产，进队列等待
        }
        //2、走到这里一定没有满？

        _q.push(in);
        //3、绝对能保证队列里面有数据，所以唤醒

        pthread_cond_signal(&_ccond);//这里可以有水位线
        pthread_mutex_unlock(&_mutex);
    }

    void pop(T* out)
    {
        pthread_mutex_lock(&_mutex);

        //1、先判断
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }

        //2、走到这里能保证，一定不为空
        *out = _q.front();
        _q.pop();

        //3、只要拿走了，就一定能保证，队列不为满，那么唤醒生产者
        pthread_cond_signal(&_pcond);//也可以有策略

        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }

private:
    bool is_empty()
    {
        return _q.empty();
    }

    bool is_full()
    {
        return _q.size() == _maxcap;
    }

private:
    std::queue<T> _q;//队列
    int _maxcap;//队列里的最大元素数量
    pthread_mutex_t _mutex;//锁
    pthread_cond_t _pcond;//生产者对应的条件变量
    pthread_cond_t _ccond;//消费者对应的条件变量
};

void Save(const std::string &message)
{
    const std::string target = "./log.txt";

    FILE *fp = fopen(target.c_str(),"a+");

    if(!fp)
    {
        std::cerr<<"fopen error"<<std::endl;
        return;
    }

    fputs(message.c_str(),fp);
    fputs("\n",fp);

    fclose(fp);

}

class SaveTask
{
    typedef std::function<void(const std::string&)> func_t;
public:
    SaveTask()
    {

    }

    SaveTask(const std::string& message,func_t func):_message(message),_func(func)
    {

    }

    void operator()()
    {
        _func(_message);
    }

    ~SaveTask()
    {

    }
private:
    std::string _message;
    func_t _func;
};
